import os
import sys
import httpx
from tqdm.auto import tqdm
import re
from bs4 import BeautifulSoup
import pandas as pd
from urllib.parse import urlparse, parse_qs

current_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.join(current_dir, ""))
sys.path.append(os.path.join(current_dir, "../"))
sys.path.append(os.path.join(current_dir, "../.."))


def param_type(source_type: str):
    """
    将文档中的数据类型转换成python数据类型
    :param source_type:
    :return:
    """
    if source_type == "str":
        return "str"
    elif source_type == "int":
        return "int"
    elif source_type == "float":
        return "float"
    elif source_type == "datetime":
        return "datetime64"
    else:
        return "str"


def indent(source: str, count: int):
    """
    代码缩进
    :param source:
    :param count:
    :return:
    """
    return "\n".join([(" " * count) + str(row) for row in source])


def columns_dict(return_list: list):
    """
    生成列类型词典
    :param return_list:
    :return:
    """
    col_str = "column_type_dict = {" + (
        ", ".join(["'" + p['name'] + "' : '" + param_type(p['data_type']) + "'" for p in return_list if
                   'name' in p and 'data_type' in p])) + "}"
    return col_str


def fix_column_name(col):
    return col


def columns_name_dict(return_list: list):
    """
    生成列中英文名称词典
    :param return_list:
    :return:
    """
    pair_list = [
        "'" + str(p['name']) + "': '" + (
            str(fix_column_name(p['desc'])) if str(p['name']) != 'ts_code' else 'ts_code') + "'"
        for
        p in return_list if 'name' in p and 'desc' in p]

    col_str = "column_name_dict = {" + (
        ", ".join(pair_list)) + "}"
    return col_str


def convert_params(params_list: list):
    """
    生成参数
    :param params_list:
    :return:
    """
    params_dict = {param['name']: param for param in params_list}
    params = [p['name'] + ": " + param_type(p['data_type']) for p in params_dict.values() if
              p['name'] != 'fields']
    params.extend(["fields:str='all'"])
    return ", ".join(params)


def all_api(api_dict_list):
    """
    生成all_api 方法,方便接口查询
    :param api_dict_list:
    :return:
    """
    return """
def all_api(keyword:str = None):
    all_api_list={api_dict_list}
    df=pd.DataFrame(all_api_list)
    if keyword is None:
        return df
    else:
        return df[(df['method'].str.contains(keyword))|(df['description'].str.contains(keyword))]        
    """.format(**locals())


def template(method: str, description: str, params: str, param_doc: str, return_doc: str, doc_url: str,
             column_dict: str, column_name_dict: str):
    """
    生成对应的接口函数
    :param module:
    :param method:
    :param description:
    :param params:
    :param param_doc:
    :param return_doc:
    :param doc_url:
    :param column_dict:
    :param column_name_dict:
    :return:
    """

    dict_value = "{}"
    return """
    def {method}(self,{params})->Query:
        \"\"\"
        {description}
        {doc_url}
        <参数>
{param_doc}
        <返回结果>
{return_doc}
        \"\"\"
        params = locals().copy()
        real_params = {dict_value}
        {column_dict}
        {column_name_dict}
        for k, v in params.items():
            if v is not None and  k !='self':
                real_params[k] = v
        return Query(method="{method}",fields=fields, params=real_params,return_column_type_dict=column_type_dict,return_column_name_dict=column_name_dict,token=self.token)    
    """.format(**locals())


def extract_doc(doc_list):
    ret_list = []
    for doc in doc_list:
        if doc is not None:
            ret_list.append((str(doc['name']) if "name" in doc else "") + ":" + (
                str(doc['data_type']) if "data_type" in doc and doc['data_type'] is not None else "") + " " + (
                                str(doc['desc']) if "desc" in doc and doc['desc'] is not None else "") + " " + (
                                str(doc['must']) if "must" in doc and doc['must'] is not None else ""))
    return ret_list


def generate_api():
    resp = httpx.get("http://www.mushuju.com/assets/js/1.js")
    data = resp.text
    links = [link for link in re.findall("href=\\\\'(\w+.html)\\\\'", data) if link[0:2] == "b_"]
    api_list = []
    codes = []
    api_dict_list = []
    methods = []
    for api in tqdm(links):
        # try:
        print(api)
        res = httpx.get("http://www.mushuju.com/" + api)
        data = res.text
        soup = BeautifulSoup(data, 'html.parser')
        dfs = pd.read_html(data, encoding='utf8')
        if data is not None and len(dfs) > 1:
            params_list = dfs[0][['参数名称', '参数类型', "是否必填", "参数描述"]].rename(
                columns={"参数名称": "name", '参数类型': "data_type", "是否必填": "must",
                         "参数描述": "desc"}).to_dict(
                orient='records')
            return_list = dfs[1][['参数名称', '参数类型', '参数描述']].rename(
                columns={"参数名称": "name", '参数类型': "data_type", '参数描述': "desc"}).to_dict(orient='records')
            params = convert_params(params_list)
            column_dict = columns_dict(return_list)
            name_dict = columns_name_dict(return_list)

            urls = [a.get("href") for a in soup.find_all("a") if "https://www.mushuju.com/data" in a.get("href")]
            if len(urls) == 0:
                continue
            parsed_url = urlparse(urls[0])
            url_param = parse_qs(parsed_url.query)
            if "from" not in url_param:
                continue
            method = url_param['from'][0].split("?")[0]
            title = "/".join([label.text for label in soup.find_all("h2")])
            codes.append(
                template(method, title, params, indent(extract_doc(params_list), 8),
                         indent(extract_doc(return_list), 8),
                         "http://www.mushuju.com/" + api,
                         column_dict, name_dict))
            methods.append(method)
            api_dict_list.append({"method": method, "description": "",
                                  'url': "http://www.mushuju.com/" + api})
            api_list.append(data)
    # except Exception as e:
    #     print(api)

    with open("api.py", 'w', encoding='utf-8') as f:
        f.write(
            "from .models import Query\nfrom datetime import datetime\nfrom .utils import store_config, load_config\nimport numpy as np\nimport datetime as dt\nfrom .cache import cache\n")
        f.write("""
import pandas as pd
import datetime as dt

    
class MuClient(object):
    def __init__(self, token=None):
        self.config=load_config()
        if token is None or len(token) < 1:
            self.token = self.config.get("token")
            if self.token is None:
                print("本地没有找到token缓存,请输入token!")
        else:
            self.token = token
            self.config['token'] = token
            store_config(self.config)
""")
        f.write("\n\n".join(codes))


if __name__ == "__main__":
    generate_api()
